package com.lsh.payment.core.service.refund;

import com.lsh.payment.api.model.basevo.ExceptionStatus;
import com.lsh.payment.api.model.refund.RefundRequest;
import com.lsh.payment.core.exception.BusinessException;
import com.lsh.payment.core.handler.IRefundChannelHandler;
import com.lsh.payment.core.handler.impl.RefundOrderStatusServiceHandler;
import com.lsh.payment.core.model.payenum.PayChannel;
import com.lsh.payment.core.model.payenum.RefundStatus;
import com.lsh.payment.core.model.refund.PayRefund;
import com.lsh.payment.core.service.refund.impl.RefundBuilder;
import com.lsh.payment.core.service.refund.impl.RefundDirector;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * Project Name: lsh-payment
 *
 * @author peter
 * @date 18/6/2
 * 北京链商电子商务有限公司
 * Package
 * desc:
 */
@Service
public class RefundOrderHandlerService implements InitializingBean {

    @Autowired
    private Map<String, IRefundChannelHandler> refundChannelHandlers;

    private Map<String, String> payChannelsHandlerName;

    @Autowired
    private PayRefundOrderService payRefundOrderService;

    @Autowired
    private RefundOrderStatusServiceHandler refundOrderStatusServiceHandler;

    @Override
    public void afterPropertiesSet() throws Exception {
        payChannelsHandlerName = new HashMap<>();
        payChannelsHandlerName.put(PayChannel.WXPAY.getName(), "wxRefundHandler");
        payChannelsHandlerName.put(PayChannel.ALIPAY.getName(), "aliRefundHandler");

        payChannelsHandlerName.put(PayChannel.PURSE_ON_CREDIT_PAY.getName(), "misPurseRefundHandler");
        payChannelsHandlerName.put(PayChannel.PURSE_PRE_PAY.getName(), "misPurseRefundHandler");
        payChannelsHandlerName.put(PayChannel.PURSE_BALANCE_PAY.getName(), "misPurseRefundHandler");
    }


    /**
     * 获取退款渠道控制器
     *
     * @param payChannel 渠道信息
     * @return 渠道控制器
     */
    public IRefundChannelHandler getRefundChannelHandler(PayChannel payChannel) {
        IRefundChannelHandler refundChannelHandler = refundChannelHandlers.get(payChannelsHandlerName.get(payChannel.getName()));

        if (refundChannelHandler == null) {
            throw new BusinessException(ExceptionStatus.E2001006.getCode(), "暂不支持该渠道的退款");
        }

        return refundChannelHandler;
    }


    /**
     * 创建退款记录
     *
     * @param refundRequest 退款请求
     * @param payChannel    退款渠道
     * @return 退款记录
     */
    public PayRefund createRefundOrder(RefundRequest refundRequest, PayChannel payChannel) {

        PayRefund payRefund = payRefundOrderService.selectRefundByRefundTradeId(refundRequest.getRefund_trade_id());
        // TODO 幂等处理
        if (payRefund != null) {
            return payRefund;
        }

        // 构建退款记录
//        payRefund = RefundFactory.payRefundBuilder(refundRequest, payChannel);
        // TODO 可以由spring维护组合关系
        IRefundBuilder refundBuilder = new RefundBuilder();
        RefundDirector refundDirector = new RefundDirector(refundBuilder);
        payRefund = refundDirector.getPayRefund(refundRequest, payChannel);

        //添加退款记录
        if (!this.addPayRefund(payRefund)) {
            throw new com.lsh.payment.core.exception.BusinessException(ExceptionStatus.E2001006.getCode(), "生成退款记录错误");
        }

        //退款记录 状态流转 并 添加 退款处理任务
        IRefundOrderStatusService refundOrderStatusService = refundOrderStatusServiceHandler.refundOrderStatusService(RefundStatus.REFUND_APPLY);

        if (refundOrderStatusService == null) {
            throw new BusinessException(ExceptionStatus.E2001006.getCode(), "暂不支持该渠道的退款");
        }

        if (!refundOrderStatusService.modifyStatus(payRefund, true)) {
            throw new com.lsh.payment.core.exception.BusinessException(ExceptionStatus.E2001006.getCode(), "退款记录状态流转失败或添加退款任务失败");
        }

        return payRefund;
    }

    /**
     * 添加退款记录
     *
     * @param payRefund 退款记录
     * @return 成功标识
     */
    protected boolean addPayRefund(PayRefund payRefund) {

        return payRefundOrderService.addRefund(payRefund) > 0;
    }

}